import jade.util.Coord;
import jade.util.Direction;
import jade.util.ExtraTools;

import java.awt.Color;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;

import processing.core.PConstants;

class Player extends Creature {
	boolean won;
	boolean changedLevel;
	boolean light;
	private boolean acted;

	private Logger logger = Logger.getLogger(Player.class.getName());
	private transient PrisonEscape parent;

	private List<Character> waitKeys;
	private List<Character> eastKeys;
	private List<Character> westKeys;
	private List<Character> northKeys;
	private List<Character> southKeys;
	private List<Character> lightKeys;

	Player(PrisonEscape parent, Dungeon dungeon, String name, int hp, int atk,
			int def, int dmg) {
		super(parent, '@', "you", dungeon, Color.white, hp, atk, def, dmg);
		onDeserialize(parent);
		visionRange = 3;
		light = true;
		changedLevel = false;
		won = false;
		logger.info("new Player");

		initKeys();
	}

	@Override
	public void act() {
		actAndTell();
	}

	// Like act() but also returns whether the move succeeded
	public boolean actAndTell() {
		if (isExpired())
			return false;

		// Descend to next level
		if (dungeon.getLevel().getTile(getX(), getY()).getLook().getCh() == '>') {
			markAsSeen();
			changedLevel = dungeon.descend();
			if (changedLevel && dungeon.getDepth() > Level.LEVELS)
				won = true;
			move = false;
			parent.playSounds(Sound.DESC);
			appendMessage("You plunge to level " + dungeon.getDepth());
			return true;
		} // Ascend to previous level
		else if (dungeon.getLevel().getTile(getX(), getY()).getLook().getCh() == '<') {
			markAsSeen();
			changedLevel = dungeon.ascend();
			move = false;
			parent.playSounds(Sound.ASC);
			appendMessage("You return to level " + dungeon.getDepth());
			return true;
		} else if (!move)
			return false;

		markAsSeen();

		acted = false;
		Direction step = null;

		if (parent.key == PConstants.CODED) {
			step = ExtraTools.keycodeToStep(parent.keyCode);
			parent.playSounds(Sound.WALK);
		} else
			step = handleKey(step);

		if (step != null)
			acted = moveOrSlide(step);

		if (acted)
			move = false;

		calcFoV();

		return acted;
	}

	private Direction handleKey(Direction step) {

		if (waitKeys.contains(parent.key)) {
			move = false;
			acted = true;
		} else if (eastKeys.contains(parent.key))
			step = Direction.E;
		else if (westKeys.contains(parent.key))
			step = Direction.W;
		else if (northKeys.contains(parent.key))
			step = Direction.N;
		else if (southKeys.contains(parent.key))
			step = Direction.S;
		else if (lightKeys.contains(parent.key)) {
			toggleLight();
			parent.playSounds(Sound.LIGHT);
			move = false;
			acted = true;
		}

		return step;
	}

	private void initKeys() {
		waitKeys = new Vector<Character>();
		eastKeys = new Vector<Character>();
		westKeys = new Vector<Character>();
		northKeys = new Vector<Character>();
		southKeys = new Vector<Character>();
		lightKeys = new Vector<Character>();
		parent.getKeys(eastKeys, "eastKeys");
		parent.getKeys(westKeys, "westKeys");
		parent.getKeys(northKeys, "northKeys");
		parent.getKeys(southKeys, "southKeys");
		parent.getKeys(lightKeys, "lightKeys");
		parent.getKeys(waitKeys, "waitKeys");
	}

	boolean isVisible(int x, int y) {
		return fov.contains(new Coord(x, y));
	}

	public void clearFov() {
		fov.clear();
	}
	
	void markAsSeen() {
		// Mark previous field of view as "seen"
		for (Coord c : fov)
			dungeon.getLevel().sight[c.getY()][c.getX()] = Sight.SEEN;
	}

	private void onDeserialize(PrisonEscape parent) {
		this.parent = parent;
	}

	private void toggleLight() {
		light = !light;
	}

}
